using Digitalmes.Domain.Entities.Mes.Processes;
using Digitalmes.Domain.Entities.Mes.Productions;

namespace Digitalmes.Application.Mes.Traceability.Products.Queries;

/// <summary>
/// 产品生产过程生产线查询命令。
/// </summary>
/// <param name="Sn">零件码</param>
/// <param name="LineId">产线 Id</param>
public sealed record GetProcessTimelineQuery(string Sn, long LineId) : IRequest<IResult<List<ProcessTimelineDto>>>;

internal sealed class GetProcessTimelineQueryHandler(IRepository<ProdCurrentState> stateRepo, IRepository<ProcRouting> routingRepo, IRepository<ProdStepExecution> stepExecutionRepo)
    : IRequestHandler<GetProcessTimelineQuery, IResult<List<ProcessTimelineDto>>>
{
    public async Task<IResult<List<ProcessTimelineDto>>> Handle(GetProcessTimelineQuery request, CancellationToken cancellationToken)
    {
        List<ProcessTimelineDto> timeline = [];
        var currentState = await stateRepo.FirstOrDefaultAsync(m => m.Sn == request.Sn && m.LineId == request.LineId, cancellationToken);
        if (currentState == null)
        {
            return Result.From(timeline);
        }

        // 查找工艺步骤
        var routing = await routingRepo.AsQueryable()
            .Includes(m => m.Steps, x => x.Operation)
            .FirstOrDefaultAsync(m => m.Id == currentState.RoutingId, cancellationToken);
        if (routing == null)
        {
            return Result.From(timeline);
        }

        // 查找执行记录（可重复过站）
        var stepExecutions = await stepExecutionRepo.GetListAsync(m => m.Sn == request.Sn && m.RoutingId == currentState.RoutingId, cancellationToken);

        // 按工艺步骤顺序找到过站的时间线，
        // 目前无法排版重复作业或是循环作业的工序流程（循环作业可能存在跳站），只按工艺步骤顺序组织时间线以及作业次数。
        foreach (var step in routing.Steps.OrderBy(s => s.Seq))
        {
            ProcessTimelineDto timeline0 = new()
            {
                OperationCode = step.Operation!.OpCode,
                Status = 1,
            };

            // 先找到已过站的记录
            var stepExecution = stepExecutions.LastOrDefault(s => s.StepId == step.Id);
            if (stepExecution != null)
            {
                timeline0.WorkstationCode = stepExecution.WorkstationCode;
                timeline0.InboundTime = stepExecution.InboundTime;
                timeline0.OutboundTime = stepExecution.OutboundTime;
                timeline0.Status = 3;
                timeline0.PassResult = stepExecution.PassResult;
                timeline0.PassCount = stepExecutions.Count(s => s.StepId == step.Id);
            }

            // 在当前正在工作的步骤
            if (currentState.Stage == WorkStageEnum.In && currentState.OperationId == step.OperationId)
            {
                timeline0.InboundTime = currentState.InboundTime;
                timeline0.Status = 2;
            }

            timeline.Add(timeline0);
        }

        return Result.From(timeline);
    }
}
